// // Copyright (c) 2009 All Right Reserved // // vl // // 2009-01-01 // Contains ... using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics.Contracts; using System.IO; using System.Linq; using System.Text; using System.Xml.Linq; using JetBrains.Annotations; using LargoCommon.Abstract; namespace LargoCommon.Music { /// /// Harmonic Stream. /// [UsedImplicitly] public class HarmonicStream { #region Fields /// /// The harmonic bars /// private List harmonicBars; #endregion #region Constructors /// /// Initializes a new instance of the class. /// public HarmonicStream() { this.HarmonicBars = new List(); } /// /// Initializes a new instance of the class. /// /// The given header. public HarmonicStream(MusicalHeader givenHeader) : this() { this.Header = givenHeader; } /// /// Initializes a new instance of the class. /// /// The Xml stream. public HarmonicStream(XElement xstream) //// MusicalHeader header : this() { if (xstream == null) { return; } XElement xheader = xstream.Element("Header"); this.Header = new MusicalHeader(xheader); var xbars = xstream.Elements("Bar"); foreach (var xb in xbars) { HarmonicBar harmonicBar = new HarmonicBar(this.Header, xb); this.HarmonicBars.Add(harmonicBar); } //// Determine modality from harmonic structures foreach (var harmonicBar in this.HarmonicBars) { var bitArray = new BitArray(this.Header.System.HarmonicOrder); foreach (var harStruct in harmonicBar.HarmonicStructures) { if (harStruct == null) { continue; } bitArray = bitArray.Or(harStruct.BitArray); } var binStruct = new BinaryStructure(this.Header.System.HarmonicSystem, bitArray); var harModality = new HarmonicModality(binStruct); harmonicBar.HarmonicModality = harModality; } } #endregion #region Properties - Xml /// Gets Xml representation. /// Property description. public virtual XElement GetXElement { get { XElement xstream = new XElement("Harmony"); xstream.Add(this.Header.GetXElement); var xheader = this.Header.GetXElement; xstream.Add(xheader); //// Structures foreach (HarmonicBar harBar in this.HarmonicBars) { //// XElement xstructs = new XElement("Structures"); XElement xbar = new XElement( "Bar", new XAttribute("Number", harBar.BarNumber), //// BarNumberInMotive new XAttribute("OriginalNumber", harBar.OriginalBarNumber), new XAttribute("Schema", harBar.RhythmicStructure != null ? harBar.RhythmicStructure.ElementSchema : string.Empty)); foreach (HarmonicStructure hstruct in harBar.HarmonicStructures) { var xstruct = hstruct.GetXElement; xbar.Add(xstruct); //// xstructs } //// xbar.Add(xstructs); xstream.Add(xbar); } return xstream; } } #endregion #region Public properties /// /// Gets or sets the harmonic motive bars. /// /// /// The harmonic motive bars. /// public IList HarmonicBars { get { Contract.Ensures(Contract.Result>() != null); if (this.harmonicBars == null) { throw new InvalidOperationException("Harmonic bars are null."); } return this.harmonicBars; } set => this.harmonicBars = (List)value ?? throw new ArgumentException("Argument cannot be empty.", nameof(value)); } /// /// Gets or sets the header. /// /// /// The header. /// public MusicalHeader Header { get; set; } /// /// Gets the name. /// /// /// The name. /// public string Name => this.Header.Name; /// /// Gets or sets the name of the file. /// /// /// The name of the file. /// public string FileName => this.Header.FileName; /// /// Gets the length. /// /// /// The length. /// public int Length => this.HarmonicBars.Count; #endregion #region Private properties #endregion #region Public static factory methods /// /// Gets the musical tectonic. /// /// The given file path. /// Returns value. [UsedImplicitly] public static HarmonicStream GetHarmonicStream(string givenFilePath) { var fileName = Path.GetFileNameWithoutExtension(givenFilePath); if (fileName == null) { return null; } //// var setup = MusicalSettings.Singleton; //// string tectonicFolder = setup.Folders.GetFolder(MusicalFolder.Tectonics); var root = XmlSupport.GetXDocRoot(givenFilePath); if (root != null && root.Name == "Harmony") { var xharmonicStream = root; var t = new HarmonicStream(xharmonicStream); //// Name = fileName.Trim() return t; } return null; } /// /// Extends the harmonic stream. /// /// The given stream. /// The given bar count. /// Returns value. [UsedImplicitly] public static HarmonicStream ExtendHarmonicStream(HarmonicStream givenStream, int givenBarCount) { if (givenStream == null || givenStream.HarmonicBars.Count == givenBarCount) { return givenStream; } var harStream = new HarmonicStream(givenStream.Header); for (int i = 0; i < givenBarCount; i++) { var cnt = givenStream.HarmonicBars.Count; var idx = i % cnt; var harBar = givenStream.HarmonicBars[idx]; harStream.HarmonicBars.Add(harBar); } return harStream; } #endregion #region String representation /// String representation of the object. /// Returns value. public override string ToString() { var s = new StringBuilder(); s.AppendFormat("HarmonicStream (Length {0})", this.HarmonicBars.Count); return s.ToString(); } /// /// Chords to string. /// /// Returns value. [UsedImplicitly] public string ChordsToString() { var s = new StringBuilder(); foreach (var harBar in this.HarmonicBars) { s.Append(harBar); s.AppendLine(" # "); } return s.ToString(); } #endregion #region Public methods /// /// Renumbers the bars. /// [UsedImplicitly] public void RenumberBars() { int barNumber = 1; foreach (var harBar in this.HarmonicBars) { if (harBar != null) { harBar.BarNumber = barNumber++; } } } /// /// Length Of Motive. /// /// First Index. /// Second Index. /// Returns value. public int LengthOfMotive(int firstIndex, int secondIndex) { var shift = 0; while (secondIndex + shift < this.HarmonicBars.Count) { var harBar = firstIndex + shift >= 0 ? this.HarmonicBars.ElementAt(firstIndex + shift) : null; var nextBar = secondIndex + shift >= 0 ? this.HarmonicBars.ElementAt(secondIndex + shift) : null; if (harBar != null && nextBar != null && string.CompareOrdinal(harBar.UniqueIdentifier, nextBar.UniqueIdentifier) == 0) { shift++; } else { break; } } return shift; } /// /// Equal Segments. /// /// First Index. /// Second Index. /// Minimal Length. /// Returns value. public bool EqualSegments(int firstIndex, int secondIndex, int minLength) { if (firstIndex + minLength > this.HarmonicBars.Count || secondIndex + minLength > this.HarmonicBars.Count) { return false; } var isEqual = true; for (var shift = 0; shift < minLength; shift++) { var harBar = firstIndex + shift > 0 ? this.HarmonicBars.ElementAt(firstIndex + shift) : null; var nextBar = secondIndex + shift > 0 ? this.HarmonicBars.ElementAt(secondIndex + shift) : null; if (harBar != null && nextBar != null && string.CompareOrdinal(harBar.UniqueIdentifier, nextBar.UniqueIdentifier) == 0) { continue; } isEqual = false; break; } return isEqual; } /// /// Write To Motive. /// /// Harmonic Motive. /// First Index. /// Length to write. public void WriteToMotive(HarmonicMotive harmonicMotive, int firstIndex, int length) { //// int firstBarNumber var newBarNumber = 1; //// 2016/08 firstBarNumber; for (var idx = firstIndex; idx < firstIndex + length; idx++) { if (idx < 0 || idx >= this.HarmonicBars.Count) { continue; } if (harmonicMotive?.HarmonicStream.HarmonicBars == null) { continue; } var harBar = this.HarmonicBars.ElementAt(idx); if (harBar == null) { continue; } var harmonicBarInMotive = (HarmonicBar)harBar.Clone(); //// 2016/08 harmonicBarInMotive.BarNumber = newBarNumber++; //// 201508 harmonicMotive.AddBar(harmonicBarInMotive); ////core harmonicMotive.Length = harmonicMotive.HarmonicBars.Count(); } } #endregion #region Private static methods #endregion #region Private methods #endregion } }